package me.pppploi8.webmcs.task;

import java.io.File;
import java.io.FileOutputStream;
import java.io.OutputStream;
import java.util.*;
import java.util.Map.Entry;

import me.pppploi8.webmcs.minecraft.server.core.McServerCore;
import me.pppploi8.webmcs.task.impl.*;
import org.quartz.CronScheduleBuilder;
import org.quartz.spi.MutableTrigger;

/**
 * 实现整个计划任务的管理和执行
 * @author pppploi8
 *
 */
public class TaskManage {
	private volatile boolean execTask = true;
	private Thread thread = null;
	private McServerCore msc;
	private Map<String,TaskCore> taskMap = new TreeMap<String,TaskCore>();
	
	public TaskManage(){
		thread = new Thread(new Runnable() {
			@Override
			public void run() {
				System.out.println("[WebMCS]计划任务线程已启动");
				while(execTask){
					try {
						long curDate = new Date().getTime()/1000;
						Iterator<Map.Entry<String, TaskCore>> it = taskMap.entrySet().iterator();
						while(it.hasNext()){
							Entry<String,TaskCore> entry = it.next();
							TaskCore task = entry.getValue();
							if (curDate >= task.getNextRuntime()){
								// 执行计划任务，并重新计算下一轮执行时间
								task.exec();
								if ("2".equals(task.getExecType())){
									System.out.println("[WebMCS]一次性任务已执行完毕，自动删除");
									it.remove();
								}else{
									task.setNextRuntime(task.getMutableTrigger().getFireTimeAfter(new Date(curDate*1000)).getTime()/1000);
								}
							}
						}
						Thread.sleep(1000);
					} catch (InterruptedException e) {}
				}
				System.out.println("[WebMCS]计划任务线程已终止");
			}
		});
		thread.start();
	}
	public TaskManage setMcServerCore(McServerCore msc){
		this.msc = msc;
		return this;
	}
	public TaskCore createTask(String id,Map<String,String>map){
		return getTaskCoreByMap(map).setId(id);
	}
	public TaskManage addTask(TaskCore task,boolean newTask){
		if (!taskMap.containsValue(task.getId())){
			task.setMcServerCore(msc);
			taskMap.put(task.getId(), task);
			if (newTask && "1".equals(task.getExecType())){
				//根据Task创建文件
				Properties p = new Properties();
				p.put("type", task.getType()+"");
				p.put("content", task.getContent());
				p.put("time", task.getTime()+"");
				p.put("exectype", task.getExecType());
				File file = new File(msc.getServerPath().getAbsolutePath() + "/task/" + task.getId() + ".task");
				file.getParentFile().mkdirs();
				try{
					OutputStream os = new FileOutputStream(file);
					p.store(os, task.getId());
					os.close();
				}catch(Exception e){
					e.printStackTrace();
				}
			}
		}
		return this;
	}
	/**
	 * 终止计划任务，但是并不会立即结束，至少要完成当前正在执行的一轮操作才会终止
	 * @return
	 */
	public TaskManage stopTask(){
		execTask = false;
		thread.interrupt();
		return this;
	}
	public boolean removeTask(String taskId){
		if(taskMap.containsKey(taskId)){
			taskMap.remove(taskId);
			File file = new File(msc.getServerPath() + "/task/" + taskId + ".task");
			if (file.exists())
				file.delete();
			return true;
		}
		return false;
	}
	public Map<String,TaskCore> getTasks(){
		return taskMap;
	}
	/**
	 * 根据map参数构造TaskCore实例(无id)
	 * @param map
	 * @return
	 */
	public static TaskCore getTaskCoreByMap(Map<String,String> map){
		TaskCore task = null;
		if ("1".equals(map.get("type"))){
			switch(map.get("content")){
			case "1":
				task = new TaskStart();
				break;
			case "2":
				task = new TaskStop();
				break;
			case "3":
				task = new TaskRestart();
				break;
			case "4":
				task = new TaskBak();
				break;
			default:
				task = TaskNull.getInstance();
				break;
			}
		} else if ("2".equals(map.get("type"))){
			task = new TaskCommond();
		} else if ("3".equals(map.get("type"))){
			task = new TaskRunProcess();
		}
		task.setExecType(map.get("exectype"));
		task.setContent(map.get("content"));
		task.setTime(map.get("time"));
		task.setMutableTrigger(CronScheduleBuilder.cronSchedule(task.getTime()).build());
		task.setNextRuntime(task.getMutableTrigger().getFireTimeAfter(task.getMutableTrigger().getStartTime()).getTime()/1000);
		return task;
	}
}
